package org.fffd.l23o6.util.strategy.train;

import java.util.*;

import jakarta.annotation.Nullable;


public class GSeriesSeatStrategy extends TrainSeatStrategy {
    public static final GSeriesSeatStrategy INSTANCE = new GSeriesSeatStrategy();

    private final Map<Integer, String> BUSINESS_SEAT_MAP = new HashMap<>();
    private final Map<Integer, String> FIRST_CLASS_SEAT_MAP = new HashMap<>();
    private final Map<Integer, String> SECOND_CLASS_SEAT_MAP = new HashMap<>();
    //seatTypes使用表驱动的方式
    private final GSeriesSeatType[] seatTypes = new GSeriesSeatType[]{GSeriesSeatType.BUSINESS_SEAT,
            GSeriesSeatType.FIRST_CLASS_SEAT, GSeriesSeatType.SECOND_CLASS_SEAT};
    //seatStartArray、seatEndArray是表驱动
    private final int[] seatStartArray;
    private final int[] seatEndArray;
    private final Map<GSeriesSeatType, Map<Integer, String>> TYPE_MAP = new HashMap<>() {{
        put(GSeriesSeatType.BUSINESS_SEAT, BUSINESS_SEAT_MAP);
        put(GSeriesSeatType.FIRST_CLASS_SEAT, FIRST_CLASS_SEAT_MAP);
        put(GSeriesSeatType.SECOND_CLASS_SEAT, SECOND_CLASS_SEAT_MAP);
    }};
    //修改：为了简单，只区分商务舱、一二等座，不区分路线和上下站
    //同样是表驱动
    private final Map<GSeriesSeatType, Integer> seatTypePriceMap = new HashMap<>() {
        {
            put(GSeriesSeatType.BUSINESS_SEAT, 500);
            put(GSeriesSeatType.FIRST_CLASS_SEAT, 200);
            put(GSeriesSeatType.SECOND_CLASS_SEAT, 100);
        }
    };


    private GSeriesSeatStrategy() {

        int counter = 0;

        for (String s : Arrays.asList("1车1A", "1车1C", "1车1F")) {
            BUSINESS_SEAT_MAP.put(counter++, s);
        }

        for (String s : Arrays.asList("2车1A", "2车1C", "2车1D", "2车1F", "2车2A", "2车2C", "2车2D", "2车2F", "3车1A", "3车1C", "3车1D", "3车1F")) {
            FIRST_CLASS_SEAT_MAP.put(counter++, s);
        }

        for (String s : Arrays.asList("4车1A", "4车1B", "4车1C", "4车1D", "4车2F", "4车2A", "4车2B", "4车2C", "4车2D", "4车2F", "4车3A", "4车3B", "4车3C", "4车3D", "4车3F")) {
            SECOND_CLASS_SEAT_MAP.put(counter++, s);
        }
        seatStartArray = new int[]{0,
                BUSINESS_SEAT_MAP.size(),
                BUSINESS_SEAT_MAP.size() + FIRST_CLASS_SEAT_MAP.size()};
        seatEndArray = new int[]{BUSINESS_SEAT_MAP.size(),
                BUSINESS_SEAT_MAP.size() + FIRST_CLASS_SEAT_MAP.size(),
                BUSINESS_SEAT_MAP.size() + FIRST_CLASS_SEAT_MAP.size() + SECOND_CLASS_SEAT_MAP.size()};

    }

    public enum GSeriesSeatType implements SeatType {
        BUSINESS_SEAT("商务座"), FIRST_CLASS_SEAT("一等座"), SECOND_CLASS_SEAT("二等座"), NO_SEAT("无座");
        private String text;

        GSeriesSeatType(String text) {
            this.text = text;
        }

        public String getText() {
            return this.text;
        }

        public static GSeriesSeatType fromString(String text) {
            for (GSeriesSeatType b : GSeriesSeatType.values()) {
                if (b.text.equalsIgnoreCase(text)) {
                    return b;
                }
            }
            return null;
        }
    }


    public @Nullable String allocSeat(int startStationIndex, int endStationIndex, GSeriesSeatType type, boolean[][] seatMap) {
        //endStationIndex - 1 = upper bound
        //TODO
        if (type.equals(GSeriesSeatType.NO_SEAT)) {
            return "无座";
        }
        Map<Integer, String> typeSeatMap = TYPE_MAP.get(type);
        int seatStart = 0, seatEnd = 0;
        //此处的for循环就体现了表驱动
        for (int i = 0; i < seatTypes.length; i++) {
            if (type.equals(seatTypes[i])) {
                seatStart = seatStartArray[i];
                seatEnd = seatEndArray[i];
                break;
            }
        }
        int resSeat = -1;
        for (int i = seatStart; i < seatEnd; i++) {
            boolean seatOK = true;
            for (int j = startStationIndex; j < endStationIndex; j++) {
                if (seatMap[j][i]) {
                    seatOK = false;
                    break;
                }
            }
            if (seatOK) {
                resSeat = i;
                break;
            }
        }
        if (resSeat != -1) {
            for (int i = startStationIndex; i < endStationIndex; i++) {
                seatMap[i][resSeat] = true;
            }
            return typeSeatMap.get(resSeat);
        } else {
            return null;
        }
    }

    public Map<GSeriesSeatType, Integer> getLeftSeatCount(int startStationIndex, int endStationIndex, boolean[][] seatMap) {
        // TODO
        HashMap<GSeriesSeatType, Integer> resMap = new HashMap<>();
        for (int i = 0; i < seatTypes.length; i++) {
            int seatCount = 0;
            int seatStart = seatStartArray[i], seatEnd = seatEndArray[i];
            for (int j = seatStart; j < seatEnd; j++) {
                boolean seatOK = true;
                for (int k = startStationIndex; k < endStationIndex; k++) {
                    if (seatMap[k][j]) {
                        seatOK = false;
                        break;
                    }
                }
                if (seatOK) {
                    seatCount++;
                }
            }
            resMap.put(seatTypes[i], seatCount);
        }
        return resMap;
    }

    public boolean[][] initSeatMap(int stationCount) {
        //提示：0-stationCount-1 每个站点有多少人在车上
        return new boolean[stationCount - 1][BUSINESS_SEAT_MAP.size() + FIRST_CLASS_SEAT_MAP.size() + SECOND_CLASS_SEAT_MAP.size()];
    }

    public Integer getPrice(GSeriesSeatType seatType) {
        return seatTypePriceMap.get(seatType);
    }

    public Integer getPrice(String seat) {
        for (GSeriesSeatType seatType : seatTypes) {
            Map<Integer, String> seatTypeMap = TYPE_MAP.get(seatType);
            for (String tempSeat : seatTypeMap.values()) {
                if (tempSeat.equals(seat)) {
                    return seatTypePriceMap.get(seatType);
                }
            }
        }
        return null;
    }
}
